package xj.graph2d.command;

import xj.graph2d.DrawShape;
import xj.graph2d.GraphDocument;
import xj.graph2d.Group;
import xj.graph2d.SimpleDrawDocument;
import xj.graph2d.SimpleDrawView;
import xj.graph2d.TextShape;
import xj.graph2d.GraphEdgeBase;
import xj.graph2d.GraphNodeBase;

public abstract class DeltaCommand 
  extends AbstractCommand {

  public DeltaCommand(SimpleDrawView view, 
		      SimpleDrawDocument doc,
		      DrawShape shape) {
    super(view, doc);
    this.shape = shape;
    x = y = 0;
  }

  public void move(float dx, float dy) {
    x += dx;
    y += dy;
  }

  public float getX() {
    return x;
  }

  public float getY() {
    return y;
  }

  public void execute() {
    _execute(true);
  }

  public void undo() {
    _execute(false);
  }

  private void _execute(boolean _forward) {
    if (shape != null) {
      boolean isDocGroup = (shape == doc.getGroup());
      DrawShape parent = shape.getParent();
      if (isDocGroup) {
	doc.setGroup(null);
      } else {
	shape.setVisible(false);
	if (doc instanceof GraphDocument && 
	    shape instanceof GraphNodeBase) {
	  GraphDocument graph = (GraphDocument) doc;
	  GraphNodeBase node = (GraphNodeBase) shape;
	  graph.setVisibleAdjacentEdges(node, false, canvas);
	}
      }
      canvas.repaintRect(shape.getRepaintRect(), true);

      if (_forward) {
	forward();
	auxForward();
      } else {
	auxBackward(false);
	backward();
	auxBackward(true);
      }

      if (isDocGroup) {
	doc.setGroup((Group) shape);
	canvas.repaintShape(shape);
      } else {
	shape.setVisible(true);
	if (doc instanceof GraphDocument) {
	  GraphDocument graph = (GraphDocument) doc;
	  if (shape instanceof GraphNodeBase) {
	    GraphNodeBase node = (GraphNodeBase) shape;
	    graph.layoutAdjacentEdges(node);
	    graph.setVisibleAdjacentEdges(node, true, canvas);
	  } else if (shape instanceof GraphEdgeBase) {
	    GraphEdgeBase edge = (GraphEdgeBase) shape;
	    //edge.adjustEnds();
	    edge.doLayout();
	  } else if (shape instanceof TextShape) {
	    while (parent != null) {
	      parent.doLayout();
	      parent = parent.getParent();
	    }
	  }
	  canvas.repaint();
	} else {
	  canvas.repaintShape(shape);
	}
      }
    }
  }

  @Override
  public String toString() {
    String s = "";
    if (shape != null) {
      if (shape instanceof TextShape) {
	TextShape text = (TextShape) shape;
	s = (text.getName() + " \"" + text.getString() + "\"");
      } else if (shape instanceof Group) {
	s = shape.toString();
      } else {
	s = (shape.getName() + " " + shape.getBoundsString());
      }
    }
    s += (" x=" + x + " y=" + y);
    if (auxActions != null) {
      int n = auxActions.size();
      for (int i = 0; i < n; i++) {
	AuxAction ac = auxActions.get(i);
	s += ("\n\t[" + ac + "]");
      }
    }
    return (getClass().getName() + ": " + s);
  }

  protected abstract void forward();

  protected abstract void backward();

  protected DrawShape shape;

  protected float x, y;

}
